<template>
  <div class="report-form-core">
    <component
      v-if="currentComponent"
      :is="currentComponent"
      ref="templateRef"
      :model-value="computedModelValue"
      :template-meta="currentTemplate"
      @update:model-value="handleTemplateModelUpdate"
      @validate="handleTemplateValidate"
      @change="emitParams"
    />
    <el-empty v-else description="请选择报表模板以配置参数" class="empty-state" />
  </div>
</template>

<script setup lang="ts">
import { computed, ref, watch, defineExpose, nextTick } from 'vue'
import { ElEmpty } from 'element-plus'
import { getTemplateMeta, type TemplateMeta } from '../templates/registry'

const props = defineProps<{
  modelValue: Record<string, any> | null
  templateCode: string | null
}>()

const emit = defineEmits<{
  (e: 'update:modelValue', value: Record<string, any>): void
  (e: 'change', value: Record<string, any>): void
  (e: 'validate', payload: { valid: boolean; errors: string[] }): void
}>()

const templateRef = ref<any>(null)

const currentTemplate = computed<TemplateMeta | null>(() => {
  return getTemplateMeta(props.templateCode || undefined)
})

const currentComponent = computed(() => {
  return currentTemplate.value?.formComponent || null
})

const localParams = ref<Record<string, any>>({})
const internalUpdate = ref(false)
const lastEmittedValue = ref<string>('')

const cloneValue = (value?: Record<string, any> | null) =>
  JSON.parse(JSON.stringify(value || {}))

// 将对象序列化为字符串用于比较（简单但有效）
const stringifyValue = (value: any): string => {
  try {
    return JSON.stringify(value)
  } catch {
    return String(value)
  }
}

// 使用 computed 创建一个稳定的值引用，避免直接传递 ref
const computedModelValue = computed(() => {
  return cloneValue(localParams.value)
})

const setLocalParams = (source?: Record<string, any> | null, emitChange = false) => {
  const nextValue = cloneValue(source)
  localParams.value = nextValue
  if (emitChange && !internalUpdate.value) {
    const stringValue = stringifyValue(nextValue)
    // 只有值真正变化时才 emit
    if (stringValue !== lastEmittedValue.value) {
      lastEmittedValue.value = stringValue
      emit('update:modelValue', cloneValue(nextValue))
      emit('change', cloneValue(nextValue))
    }
  }
}

// 深度合并对象
const deepMerge = (target: any, source: any): any => {
  if (!source || typeof source !== 'object') return target
  if (!target || typeof target !== 'object') return source
  
  const result = { ...target }
  
  for (const key in source) {
    if (source.hasOwnProperty(key)) {
      const sourceValue = source[key]
      const targetValue = target[key]
      
      // 如果两个值都是对象且都不是数组，则递归合并
      if (
        sourceValue &&
        typeof sourceValue === 'object' &&
        !Array.isArray(sourceValue) &&
        targetValue &&
        typeof targetValue === 'object' &&
        !Array.isArray(targetValue)
      ) {
        result[key] = deepMerge(targetValue, sourceValue)
      } else {
        // 否则直接使用 source 的值（如果存在）
        result[key] = sourceValue !== undefined ? sourceValue : targetValue
      }
    }
  }
  
  return result
}

const mergeParams = (source?: Record<string, any> | null, emitChange = false) => {
  const defaults = currentTemplate.value?.defaultParams || {}
  // 使用深度合并，确保嵌套对象不会被完全替换
  const merged = deepMerge(defaults, source || {})
  setLocalParams(merged, emitChange)
}

const emitParams = () => {
  // 子组件通过 change 事件通知，这里只 emit change
  emit('change', cloneValue(localParams.value))
}

const handleTemplateValidate = (payload: { valid: boolean; errors: string[] }) => {
  emit('validate', payload)
}

const handleTemplateModelUpdate = (value: Record<string, any>) => {
  // 标记这是来自子组件的更新，避免触发 watch
  internalUpdate.value = true
  
  // 更新本地状态
  const nextValue = cloneValue(value)
  const stringValue = stringifyValue(nextValue)
  
  // 只有值真正变化时才更新和 emit
  if (stringValue !== lastEmittedValue.value) {
    localParams.value = nextValue
    lastEmittedValue.value = stringValue
    // 直接 emit 给父组件
    emit('update:modelValue', cloneValue(nextValue))
    emit('change', cloneValue(nextValue))
  }
  
  nextTick(() => {
    internalUpdate.value = false
  })
}

watch(
  () => props.modelValue,
  (val) => {
    // 如果正在从子组件更新，则跳过
    if (internalUpdate.value) return
    
    // 比较外部值和当前值，避免不必要的更新
    const currentStringValue = stringifyValue(localParams.value)
    const externalStringValue = stringifyValue(val)
    
    // 如果值相同，不需要更新
    if (currentStringValue === externalStringValue) return
    
    // 处理 undefined、null 的情况，确保传递的是对象或 null
    if (val === null || val === undefined) {
      // 如果外部传入 null 或 undefined，使用模板默认参数
      mergeParams({}, false)
    } else if (typeof val === 'object') {
      // 如果是对象（包括空对象），合并外部参数和模板默认参数
      // 使用深度合并，确保嵌套对象（如 source_tables, time_range）正确合并
      mergeParams(val, false)
    } else {
      // 其他类型，使用模板默认参数
      mergeParams({}, false)
    }
  },
  { deep: true, immediate: true }
)

watch(
  () => props.templateCode,
  () => {
    // 模板切换时优先使用外部参数，否则回落到模板默认参数
    // 注意：这里不设置 internalUpdate，因为这是外部触发的模板切换
    if (props.modelValue && Object.keys(props.modelValue).length > 0) {
      // 如果有外部参数，使用外部参数（深度合并）
      mergeParams(props.modelValue, false)
    } else if (currentTemplate.value?.defaultParams) {
      // 否则使用模板默认参数
      mergeParams(currentTemplate.value.defaultParams, false)
    }
  }
)

const validate = async () => {
  if (templateRef.value?.validate) {
    return await templateRef.value.validate()
  }
  return true
}

defineExpose({ validate })
</script>

<style scoped>
.report-form-core {
  width: 100%;
}

.empty-state {
  padding: 60px 0;
}
</style>

